package org.nw.service.impl;

import java.io.File;
import java.lang.reflect.Field;
import java.util.Date;
import java.util.Map;

import nc.vo.pub.AggregatedValueObject;
import nc.vo.pub.CircularlyAccessibleValueObject;
import nc.vo.pub.SuperVO;
import nc.vo.pub.VOStatus;
import nc.vo.pub.lang.UFDate;

import org.apache.commons.lang.StringUtils;
import org.nw.BillStatus;
import org.nw.exception.BusiException;
import org.nw.exp.BillExcelImporter;
import org.nw.exp.ExcelImporter;
import org.nw.jf.vo.UiBillTempletVO;
import org.nw.jf.vo.UiQueryTempletVO;
import org.nw.service.IBillService;
import org.nw.service.ServiceHelper;
import org.nw.utils.BillnoHelper;
import org.nw.utils.CorpHelper;
import org.nw.vo.ParamVO;
import org.springframework.transaction.annotation.Transactional;

import com.uft.webnc.util.ReflectionUtils;

/**
 * 单据的处理逻辑
 * 
 * @author xuqc
 * @date 2012-7-7 上午10:52:13
 */
public abstract class AbsBillServiceImpl extends AbsToftServiceImpl implements IBillService {

	/**
	 * 对于单据类型，就是单据号
	 */
	@Override
	public String getCodeFieldCode() {
		return "vbillno";
	}

	public String getBillStatusField() {
		return "vbillstatus";
	}

	@Override
	public UiBillTempletVO getBillTempletVO(String templateID) {
		UiBillTempletVO templetVO = super.getBillTempletVO(templateID);
		templetVO.setBillType(this.getBillType());
		return templetVO;
	}

	@Override
	public Map<String, Object> getHeaderDefaultValues(ParamVO paramVO) {
		Map<String, Object> values = super.getHeaderDefaultValues(paramVO);
		values.put(getBillStatusField(), BillStatus.NEW);// 默认新建状态
		values.put("dbilldate", new UFDate(new Date()));// 默认单据日期
		return values;
	}

	/**
	 * 对于单据类型，就是设置单据号
	 */
	@Override
	public void setCodeField(CircularlyAccessibleValueObject parentVO, ParamVO paramVO) {
		if(StringUtils.isNotBlank(getCodeFieldCode())) {
			// 子类继承了该方法，说明希望使用编码规则
			Object codeObj = parentVO.getAttributeValue(getCodeFieldCode());
			if(codeObj == null || StringUtils.isBlank(codeObj.toString())) {
				// 如果没有录入编码，则按照规则生成一个
				String billno = BillnoHelper.generateBillno(this.getBillType());
				if(StringUtils.isBlank(billno)) {
					throw new RuntimeException("可能没有定义单据号规则，无法生成编码！");
				}
				SuperVO superVO = this.getByCodeWithNoDr(billno);
				while(superVO != null) {
					// 该订单号已经存在
					billno = BillnoHelper.generateBillno(this.getBillType());
					superVO = this.getByCodeWithNoDr(billno);
				}
				parentVO.setAttributeValue(getCodeFieldCode(), billno);
			}
		}
	}

	/**
	 * 对于单据，一般只能查询本公司及其子公司的单据
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public String buildLoadDataCondition(String params, ParamVO paramVO, UiQueryTempletVO templetVO) {
		String fCond = "1=1";
		String cond = parseCondition(params, paramVO, templetVO);
		if(StringUtils.isNotBlank(cond)) {
			fCond += " and ";
			fCond += cond;
		}

		if(!paramVO.isBody()) {
			Class clazz = ServiceHelper.getVOClass(this.getBillInfo(), paramVO);
			try {
				SuperVO superVO = (SuperVO) clazz.newInstance();
				Field pk_corp = ReflectionUtils.getDeclaredField(superVO, "pk_corp");// 如果存在pk_corp字段
				if(pk_corp != null) {
					String corpCond = CorpHelper.getCurrentCorpWithChildren(superVO.getTableName());
					if(StringUtils.isNotBlank(corpCond)) {
						fCond += " and " + corpCond;
					}
				}
			} catch(Exception e) {
				e.printStackTrace();
			}
		}
		return fCond;
	}

	@Override
	protected void processCopyVO(AggregatedValueObject copyVO, ParamVO paramVO) {
		super.processCopyVO(copyVO, paramVO);
		CircularlyAccessibleValueObject parentVO = copyVO.getParentVO();
		parentVO.setAttributeValue("vbillstatus", BillStatus.NEW); // 默认新增状态
		parentVO.setAttributeValue("vbillno", null); // 清空单据号
	}

	/**
	 * 返回确认状态，这里为了方便定义确认按钮的逻辑，子类只需要定义单据的确认状态的值
	 * 
	 * @return
	 */
	protected Integer getConfirmStatus() {
		return null;
	}

	@Transactional
	public Map<String, Object> confirm(ParamVO paramVO) {
		AggregatedValueObject billVO = queryBillVO(paramVO);
		processBeforeConfirm(billVO, paramVO);
		CircularlyAccessibleValueObject parentVO = billVO.getParentVO();
		Object oBillStatus = parentVO.getAttributeValue(getBillStatusField());
		if(oBillStatus != null) {
			int billStatus = Integer.parseInt(oBillStatus.toString());
			if(BillStatus.NEW != billStatus) {
				throw new RuntimeException("只有[新建]状态的单据才能进行确认！");
			}
		}
		parentVO.setStatus(VOStatus.UPDATED);
		parentVO.setAttributeValue(getBillStatusField(), getConfirmStatus()); // 设置成已确认
		dao.saveOrUpdate(billVO);
		return execFormula4Templet(billVO, paramVO);
	}

	/**
	 * 执行confirm前的动作
	 * 
	 * @param billVO
	 */
	public void processBeforeConfirm(AggregatedValueObject billVO, ParamVO paramVO) {

	}

	@Transactional
	public Map<String, Object> unconfirm(ParamVO paramVO) {
		AggregatedValueObject billVO = queryBillVO(paramVO);
		processBeforeUnconfirm(billVO, paramVO);
		CircularlyAccessibleValueObject parentVO = billVO.getParentVO();
		Object oBillStatus = parentVO.getAttributeValue(getBillStatusField());
		if(oBillStatus != null) {
			int billStatus = Integer.parseInt(oBillStatus.toString());
			if(getConfirmStatus() != billStatus) {
				throw new RuntimeException("只有[确认]状态的单据才能进行反确认,单据号："
						+ parentVO.getAttributeValue(this.getCodeFieldCode()) + "；");
			}
		}
		parentVO.setStatus(VOStatus.UPDATED);
		parentVO.setAttributeValue(getBillStatusField(), BillStatus.NEW); // 设置成新建
		dao.saveOrUpdate(billVO);
		Map<String, Object> retMap = execFormula4Templet(billVO, paramVO);
		return retMap;
	}

	/**
	 * 执行unconfirm前的动作
	 * 
	 * @param billVO
	 */
	public void processBeforeUnconfirm(AggregatedValueObject billVO, ParamVO paramVO) throws BusiException {

	}

	@Transactional
	public Map<String, Object> vent(ParamVO paramVO) {
		return null;
	}

	@Transactional
	public Map<String, Object> unvent(ParamVO paramVO) {
		return null;
	}

	@Override
	protected void processBeforeDelete(AggregatedValueObject billVO) {
		super.processBeforeDelete(billVO);
		// 只能删除单据状态为新增的单据
		CircularlyAccessibleValueObject parentVO = billVO.getParentVO();
		Object vbillstatus = parentVO.getAttributeValue(getBillStatusField());
		if(vbillstatus == null) {
			// 单据状态为空，这个单据不正常，可以执行删除操作，比如可能是测试数据
			logger.warn("该单据的单据状态为空,这不应该出现！");
		} else {
			if(Integer.parseInt(vbillstatus.toString()) != BillStatus.NEW) {
				throw new RuntimeException("只能删除单据状态为[新建]的单据！");
			}
		}
	}

	public String doImport(ParamVO paramVO, File file) throws Exception {
		ExcelImporter importer = new BillExcelImporter(paramVO, this);
		importer._import(file);
		return importer.getLog();
	}
}
